/***************************************************************************
 *   Copyright (C) 2009 by umbacos@gmail.com                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "udm-common.h"

static char* response;
static size_t response_size, response_len;

unsigned char x2c ( unsigned char * what ) {
	int digit;

	digit = ( what[0] >= 'A' ? ( ( what[0] & 0xdf ) - 'A' ) + 10 : ( what[0] - '0' ) );
	digit *= 16;
	digit += ( what[1] >= 'A' ? ( ( what[1] & 0xdf ) - 'A' ) + 10 : ( what[1] - '0' ) );
	return ( digit & 0xff );
}

char * utf_8 ( char * c ) {
// input: a string in the form of "%XX" no trailing \0 required

	char s[2];

	switch ( c[1] ) {
		case 'A':

			switch ( c[2] ) {
				case '0': return " "; //NO-BREAK SPACE
				case '1': return "¡"; //INVERTED EXCLAMATION MARK
				case '2': return "¢"; //CENT SIGN
				case '3': return "£"; //POUND SIGN
				case '4': return "¤"; //CURRENCY SIGN
				case '5': return "¥"; //YEN SIGN
				case '6': return "¦"; //BROKEN BAR
				case '7': return "§"; //SECTION SIGN
				case '8': return "¨"; //DIAERESIS
				case '9': return "©"; //COPYRIGHT SIGN
				case 'A': return "ª"; //FEMININE ORDINAL INDICATOR
				case 'B': return "«"; //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
				case 'C': return "¬"; //NOT SIGN
				case 'D': return "­"; //SOFT HYPHEN
				case 'E': return "®"; //REGISTERED SIGN
				case 'F': return "¯"; //MACRON
			}

			break;

		case 'B':

			switch ( c[2] ) {
				case '0': return "°"; //DEGREE SIGN
				case '1': return "±"; //PLUS-MINUS SIGN
				case '2': return "²"; //SUPERSCRIPT TWO
				case '3': return "³"; //SUPERSCRIPT THREE
				case '4': return "´"; //ACUTE ACCENT
				case '5': return "µ"; //MICRO SIGN
				case '6': return "¶"; //PILCROW SIGN
				case '7': return "·"; //MIDDLE DOT
				case '8': return "¸"; //CEDILLA
				case '9': return "¹"; //SUPERSCRIPT ONE
				case 'A': return "º"; //MASCULINE ORDINAL INDICATOR
				case 'B': return "»"; //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
				case 'C': return "¼"; //VULGAR FRACTION ONE QUARTER
				case 'D': return "½"; //VULGAR FRACTION ONE HALF
				case 'E': return "¾"; //VULGAR FRACTION THREE QUARTERS
				case 'F': return "¿"; //INVERTED QUESTION MARK
			}

			break;

		case 'C':

			switch ( c[2] ) {
				case '0': return "À"; //LATIN CAPITAL LETTER A WITH GRAVE
				case '1': return "Á"; //LATIN CAPITAL LETTER A WITH ACUTE
				case '2': return "Â"; //LATIN CAPITAL LETTER A WITH CIRCUMFLEX
				case '3': return "Ã"; //LATIN CAPITAL LETTER A WITH TILDE
				case '4': return "Ä"; //LATIN CAPITAL LETTER A WITH DIAERESIS
				case '5': return "Å"; //LATIN CAPITAL LETTER A WITH RING ABOVE
				case '6': return "Æ"; //LATIN CAPITAL LETTER AE
				case '7': return "Ç"; //LATIN CAPITAL LETTER C WITH CEDILLA
				case '8': return "È"; //LATIN CAPITAL LETTER E WITH GRAVE
				case '9': return "É"; //LATIN CAPITAL LETTER E WITH ACUTE
				case 'A': return "Ê"; //LATIN CAPITAL LETTER E WITH CIRCUMFLEX
				case 'B': return "Ë"; //LATIN CAPITAL LETTER E WITH DIAERESIS
				case 'C': return "Ì"; //LATIN CAPITAL LETTER I WITH GRAVE
				case 'D': return "Í"; //LATIN CAPITAL LETTER I WITH ACUTE
				case 'E': return "Î"; //LATIN CAPITAL LETTER I WITH CIRCUMFLEX
				case 'F': return "Ï"; //LATIN CAPITAL LETTER I WITH DIAERESIS
			}

			break;

		case 'D':

			switch ( c[2] ) {
				case '0': return "Ð"; //LATIN CAPITAL LETTER ETH
				case '1': return "Ñ"; //LATIN CAPITAL LETTER N WITH TILDE
				case '2': return "Ò"; //LATIN CAPITAL LETTER O WITH GRAVE
				case '3': return "Ó"; //LATIN CAPITAL LETTER O WITH ACUTE
				case '4': return "Ô"; //LATIN CAPITAL LETTER O WITH CIRCUMFLEX
				case '5': return "Õ"; //LATIN CAPITAL LETTER O WITH TILDE
				case '6': return "Ö"; //LATIN CAPITAL LETTER O WITH DIAERESIS
				case '7': return "×"; //MULTIPLICATION SIGN
				case '8': return "Ø"; //LATIN CAPITAL LETTER O WITH STROKE
				case '9': return "Ù"; //LATIN CAPITAL LETTER U WITH GRAVE
				case 'A': return "Ú"; //LATIN CAPITAL LETTER U WITH ACUTE
				case 'B': return "Û"; //LATIN CAPITAL LETTER U WITH CIRCUMFLEX
				case 'C': return "Ü"; //LATIN CAPITAL LETTER U WITH DIAERESIS
				case 'D': return "Ý"; //LATIN CAPITAL LETTER Y WITH ACUTE
				case 'E': return "Þ"; //LATIN CAPITAL LETTER THORN
				case 'F': return "ß"; //LATIN SMALL LETTER SHARP S
			}

			break;

		case 'E':

			switch ( c[2] ) {
				case '0': return "à"; //LATIN SMALL LETTER A WITH GRAVE
				case '1': return "á"; //LATIN SMALL LETTER A WITH ACUTE
				case '2': return "â"; //LATIN SMALL LETTER A WITH CIRCUMFLEX
				case '3': return "ã"; //LATIN SMALL LETTER A WITH TILDE
				case '4': return "ä"; //LATIN SMALL LETTER A WITH DIAERESIS
				case '5': return "å"; //LATIN SMALL LETTER A WITH RING ABOVE
				case '6': return "æ"; //LATIN SMALL LETTER AE
				case '7': return "ç"; //LATIN SMALL LETTER C WITH CEDILLA
				case '8': return "è"; //LATIN SMALL LETTER E WITH GRAVE
				case '9': return "é"; //LATIN SMALL LETTER E WITH ACUTE
				case 'A': return "ê"; //LATIN SMALL LETTER E WITH CIRCUMFLEX
				case 'B': return "ë"; //LATIN SMALL LETTER E WITH DIAERESIS
				case 'C': return "ì"; //LATIN SMALL LETTER I WITH GRAVE
				case 'D': return "í"; //LATIN SMALL LETTER I WITH ACUTE
				case 'E': return "î"; //LATIN SMALL LETTER I WITH CIRCUMFLEX
				case 'F': return "ï"; //LATIN SMALL LETTER I WITH DIAERESIS
			}

			break;

		case 'F':

			switch ( c[2] ) {
				case '0': return "ð"; //LATIN SMALL LETTER ETH
				case '1': return "ñ"; //LATIN SMALL LETTER N WITH TILDE
				case '2': return "ò"; //LATIN SMALL LETTER O WITH GRAVE
				case '3': return "ó"; //LATIN SMALL LETTER O WITH ACUTE
				case '4': return "ô"; //LATIN SMALL LETTER O WITH CIRCUMFLEX
				case '5': return "õ"; //LATIN SMALL LETTER O WITH TILDE
				case '6': return "ö"; //LATIN SMALL LETTER O WITH DIAERESIS
				case '7': return "÷"; //DIVISION SIGN
				case '8': return "ø"; //LATIN SMALL LETTER O WITH STROKE
				case '9': return "ù"; //LATIN SMALL LETTER U WITH GRAVE
				case 'A': return "ú"; //LATIN SMALL LETTER U WITH ACUTE
				case 'B': return "û"; //LATIN SMALL LETTER U WITH CIRCUMFLEX
				case 'C': return "ü"; //LATIN SMALL LETTER U WITH DIAERESIS
				case 'D': return "ý"; //LATIN SMALL LETTER Y WITH ACUTE
				case 'E': return "þ"; //LATIN SMALL LETTER THORN
				case 'F': return "ÿ"; //LATIN SMALL LETTER Y WITH DIAERESIS
			}

			break;

		default:
			s[0] = x2c ( &c[1] );
			s[1] = '\0';
			return strdup ( s );
	}
}

void unescape_url ( unsigned char *url ) {
	int i, j;
	char * utf;

	for ( i = 0, j = 0; url[j]; ++i, ++j ) {
		if ( ( url[i] = url[j] ) != '%' ) continue;
		if ( !url[j + 1] || !url[j + 2] )  break;
		utf = utf_8 ( &url[j] );
		url[i] = utf[0];
		if ( utf[1] ) {url[i+1] = utf[1];i++;}
		j += 2;
	}

	url[i] = '\0';
}

void print_headers ( int final ) {

	printf ( "Content-type: text/html;charset=utf-8\015\012" );
	printf ( "Pragma: no-cache\015\012" );
	printf ( "Cache-Control: no-cache,no-store\015\012" );
	printf ( "Expires: 0\015\012" );

	if ( final ) printf ( "\n" );

}

static void add_to_buf ( char** bufP, size_t* bufsizeP, size_t* buflenP, char* str, size_t len ) {
	if ( *bufsizeP == 0 ) {
		*bufsizeP = len + 500;
		*buflenP = 0;
		*bufP = ( char* ) xmalloc ( *bufsizeP );
	} else if ( *buflenP + len >= *bufsizeP ) {
		*bufsizeP = *buflenP + len + 500;
		*bufP = ( char* ) realloc ( ( void* ) * bufP, *bufsizeP );
	}

	( void ) memmove ( & ( ( *bufP ) [*buflenP] ), str, len );
	*buflenP += len;
	( *bufP ) [*buflenP] = '\0';
}

void send_response ( void ) {
#ifdef DEBUG
	mylog ( "DUMP RESPONSE:\n", response );
#endif
	printf ( "%s", response );
}

void add_to_response ( char* str ) {
	add_to_buf ( &response, &response_size, &response_len, str, strlen ( str ) );
}

void init_response ( void ) {
	response_size = 0;
}

void add_headers ( int final ) {

	add_to_response ( "Content-type: text/html;charset=utf-8\015\012" );
	add_to_response ( "Pragma: no-cache\015\012" );
	add_to_response ( "Cache-Control: no-cache,no-store\015\012" );
	add_to_response ( "Expires: 0\015\012" );

	if ( final ) add_to_response ( "\n" );

}

/* Error and Msg */
void send_message ( char * msg, char * inf ) {
#ifdef DEBUG
	mylog ( msg, inf );
#endif
	init_response();
	add_headers ( FALSE );

	if ( strstr ( msg, "Location" ) ) {
		add_to_response ( "Location: " );
		add_to_response ( inf );
		add_to_response ( "\n\n" );
	} else {
		add_to_response ( "\n" );
		add_to_response ( msg );

		if ( inf == NULL ) {
			add_to_response ( "(NULL)" );
		} else {
			if ( strlen ( inf ) > 0 ) add_to_response ( " " );
			add_to_response ( inf );
		}
	}

	send_response();

	exit ( 0 );
}
